Jak z pewnością udało Ci się już zauważyć, routing jest zagadnieniem dużo prostszym od Reduksa. Właśnie dlatego więcej czasu zajęło nam przygotowanie odpowiednich widoków niż sama konfiguracja routingu.
Mamy nadzieję, że na tym etapie tworzenie komponentów nie jest już dla Ciebie czarną magią – dlatego skupimy się na trenowaniu umiejętności związanych z routingiem i Reduksem. W tym celu zaczniemy nowy projekt! A właściwie, będziemy go kontynuować...
Za chwilę pobierzesz projekt agencji turystycznej, który jest w zaawansowanym stadium rozwoju. Twoim zadaniem będzie dokończenie go, a konkretniej:
- w projekcie brakuje routingu dla niektórych widoków,
- nie działa filtrowanie wycieczek.
Szczegółowy opis zadania znajdziesz poniżej – najpierw jednak musimy zapoznać się z projektem.
Uruchomienie projektu
Zacznij od założenia na GitHubie nowego repozytorium – travel-agency. Następnie sklonuj je i rozpakuj do niego zawartość paczki, dostępnej pod poniższym linkiem.
Pobierz pliki projektu
Następnie zainstaluj pakiety za pomocą komendy npm install i uruchom projekt – npm start. Twoim oczom powinna ukazać się strona główna naszej agencji turystycznej!
Początkowy stan projektu
Szybko możesz zorientować się, że nasz projekt wymaga dokończenia – działa w nim tylko strona główna, lista wycieczek oraz strona kontaktowa. W nagłówku strony możesz też znaleźć linki Countries oraz Regions, ale one nie działają. Na liście wycieczek można kliknąć w każdą z nich, co również przeniesie nas na stronę 404 (czyli "nie znaleziono takiej strony"). Możesz się też domyślać, że na liście krajów z niedziałającej strony Countries będą dostępne linki do krajów – które też nie będą działać.
Mamy jednak dla Ciebie dobrą wiadomość – w plikach projektu znajdziesz wszystkie te niedziałające widoki! Oznacza to, że wystarczy skonfigurować poprawny routing, aby strona ożyła!
Nieco większym wyzwaniem będzie usprawnienie filtrów na liście wycieczek. Całe szczęście działa chociaż jeden z filtrów – wyszukiwanie. Będziemy mogli się na nim wzorować przy dodawaniu funkcjonalności pozostałych filtrów.
Analiza plików projektu
Ten projekt pod wieloma aspektami jest podobny do aplikacji to-do, którą rozwijaliśmy do tej pory. Znajdziesz w nim jednak kilka istotnych różnic. Omówimy je sobie pokrótce, aby łatwiej było Ci zrozumieć działanie projektu.
Konfiguracja projektu
Wszystko poza katalogiem src jest prawie identyczne, jak w projekcie to-do. Oczywiście najbardziej kluczowym plikiem jest package.json, w którym zmieniły się tylko dodatkowe pakiety. Dodaliśmy react-flexbox-grid (który za chwilę omówimy), a usunęliśmy niewykorzystywane w tym projekcie shortid (oraz react-beautiful-dnd z submodułu dla chętnych w poprzednim module).
Nadal używamy ESLinta oraz Husky'ego, który lintuje nasze pliki przy zapisywaniu commita. Pamiętaj, aby czytać komunikaty w terminalu po każdej próbie zapisu commita – jeśli ESLint wykryje błąd, commit nie zostanie zapisany!
W konfiguracji webpacka również mamy tylko kosmetyczną zmianę – uwzględniliśmy flexboxgrid z pakietu react-flexbox-grid.
Poza tymi zmianami wszystko powinno wyglądać znajomo.
Struktura katalogu src
W katalogu źródłowym już na pierwszy rzut oka zauważysz dwie nowości! Pierwszą z nich jest katalog utils, który stworzyliśmy na potrzeby wydzielenia nieco rozbudowanej funkcji, wykorzystywanej w komponencie App. Druga zmiana dotyczy właśnie tego komponentu – znalazł się bezpośrednio w katalogu src!
Zmieniliśmy lokalizację tego komponentu, ponieważ jego rola istotnie różni się od pozostałych komponentów. Służy nam przede wszystkim do konfiguracji routingu, a nie jest odpowiedzialny za żadne elementy widoczne na stronie. Skoro jest plikiem zarządzającym aplikacją, to wylądował na równi z index.js.
Kolejną nowość znajdziesz w katalogu src/components – znajdują się w nim cztery katalogi, grupujące komponenty. W poprzednim projekcie wszystkie komponenty znajdowały się bezpośrednio w components, ale jest to podejście mało odporne na rozwój projektu. Nawet w aplikacji to-do mogło być dla Ciebie irytujące znalezienie plików konkretnego komponentu. Tym razem będzie trochę większy porządek, ponieważ podzieliliśmy je na cztery kategorie:
layout – to komponenty związane z układem elementów na stronie oraz elementy widniejące na każdej stronie (Header),
views – w tym katalogu znajdziesz komponenty wyświetlane za pomocą routingu, czyli podstrony naszej aplikacji,
features – fragmenty widoków znajdujących się w views, czyli np. pojedynczy box z listy wycieczek,
common – podstawowe komponenty wykorzystywane do różnych celów, takie jak np. guziki, ikony czy wrappery obrazków.
Pamiętaj, że ten podział nie jest jedynym poprawnym podejściem. Dlatego przy tworzeniu nowego komponentu, nigdy nie poświęcaj więcej niż 2-3 minut na decyzję, gdzie go umieścić (a zarazem katalogu w components). W razie wątpliwości możesz kierować się rozmiarem komponentu: views składają się z features, które wykorzystują common – a layout to układ strony i jego stałe elementy.
W tych czterech katalogach znajdziesz foldery komponentów, których zawartość znasz już z poprzedniego projektu. W każdym z nich znajduje się plik komponentu oraz mogą się w nim znaleźć (jeśli są używane) style i kontener.
Uczulamy na to, aby nie przywiązywać się do tego podziału, ponieważ jest to kwestia preferencji programisty czy zespołu projektowego. Nie ma co do tego żadnych znaczących wytycznych – poza jednym: należy wybrać podział wedle funkcjonalności lub rodzaju plików.
My od początku stosujemy podział funkcjonalny, czyli np. widok Trips posiada swój katalog, w którym znajdziesz też jego kontener i style. Dotyczy to również Reduksa – selektory, typy akcji i ich selektory, oraz reducer, znajdują się w jednym pliku dla danego fragmentu stanu aplikacji (np. tripsRedux.js).
Drugim podejściem, które obecnie jest coraz rzadziej wykorzystywane, jest podział ze względu na rodzaj plików – w tym podejściu znajdziesz osobne katalogi na komponenty, kontenery, style, akcje, reducery i selektory. Przez większość społeczności reactowej, to podejście uznaje się za mniej logiczne i utrudniające rozwój projektu – ale wspominamy o nim, ponieważ możesz się z nim spotkać, dołączając do projektu w swojej pierwszej pracy.
Katalog src/data
Tym razem dane źródłowe znajdują się w plikach .json – zobaczysz jednak (np. w store.js), że ich wykorzystanie nie sprawi nam żadnego problemu.
W tym samym katalogu znajdziesz również plik tripGenerator.js, który nie jest używany w projekcie. Jest to plik zawierający konfigurację, wykorzystywaną w generatorze plików JSON. Użyliśmy jej do wygenerowania pliku trips.json, czyli wszystkich wycieczek dostępnych na stronie naszej agencji turystycznej.
Zawarliśmy ten plik na wypadek, gdyby miał Ci się przydać do zmiany produktów oferowanych na stronie. Przy okazji, chcieliśmy pokazać Ci, w jaki sposób można tworzyć przykładowe dane do aplikacji. Dzięki temu w naszej aplikacji nie mamy wycieczek o nazwach "Trip 1", "Trip 2" itd.
Nie przejmuj się złożonością pliku tripGenerator.js – w przykładowej konfiguracji możesz zobaczyć, że konfigurację można napisać w bardzo prosty sposób. Rozbudowaliśmy ją jednak, aby np. cena wycieczki była proporcjonalna do jej długości (liczby dni). W tym pliku znajdziesz też pełną listę krajów, dostępnych w countries.json – większość z nich jest zakomentowana, aby w losowym zestawie danych było po kilka wycieczek do tego samego kraju. Możesz jednak dowolnie zmieniać tę konfigurację.
Redux
Reduksa używamy bardzo podobnie do poprzedniego projektu, z jedną istotną różnicą. W store.js możesz zobaczyć, że jako storeReducer używamy własnej funkcji, która uruchamia globalReducer, a dopiero potem połączone reducery cząstkowe.
Dzięki temu mogliśmy w pliku globalRedux.js zdefiniować reducer, który obsługuje cały stan aplikacji, a nie tylko jego fragment. Potrzebujemy tego do jednoczesnego ustawienia kilku właściwości znajdujących się w stanie aplikacji.
Konkretniej rzecz biorąc, chodzi o funkcję parseTrips.js, którą znajdziesz w katalogu src/utils. Wykorzystujemy ją w komponencie App. Przyjmuje ona listę wszystkich wycieczek, a szczegółowe informacje o krajach pobiera z pliku countries.json, ale w stanie nie są zapisywane dane wszystkich krajów – tworzy zestawienie wyłącznie tych krajów, regionów i subregionów, do których oferujemy wycieczki.
W pliku countries.json każdy kraj posiada przypisany region i subregion – dlatego tworzymy też ich zestawienie, aby móc wyświetlać kraje (lub wycieczki) wedle tego podziału.
Poza globalnym reducerem reszta reduksowego magazynu działa tak jak wcześniej. W poszczególnych plikach ...Redux.js znajdziesz selektory, typy akcji z ich kreatorami, oraz reducery. Nie zdziw się, że w niektórych z nich została zakomentowana cała część dotycząca akcji i reducera – jeśli dla danego typu danych nie używamy akcji, zostawiliśmy zakomentowaną strukturę, która ułatwi Ci w przyszłości rozwój projektu.
Layout strony
Jak wspomnieliśmy wcześniej, w tym projekcie używamy pakietu react-flexbox-grid, który dostarcza nam komponentów:
Grid – stosujemy go zamiast Container i nie zagnieżdżamy kolejnego Grid w nim,
Row – czyli wiersz, w którym umieszczamy kolumny,
Col – to są kolumny, którym możemy nadawać szerokości dla różnych rozdzielczości.
Przykłady jego zastosowania znajdziesz na stronie tego pakietu oraz w dokumentacji na GitHubie.
Wykorzystaliśmy tę paczkę, mimo jej ubogiej dokumentacji, ponieważ dostarcza nam wszystkie funkcjonalności, jakie były nam potrzebne w tym projekcie. Pozwala na wykorzystanie grida, bardzo podobnego do bootstrapowego, bez konieczności załączania całego bootstrapa.
Dzięki temu nie musieliśmy samodzielnie tworzyć komponentów odpowiedzialnych za układ kolumnowy, co jest znacznym ułatwieniem przy tworzeniu projektu.
Uzupełnieniem tego pakietu jest komponent Section, który znajdziesz w src/layout, pozwalający nam na stosowanie różnych wariantów ostylowanej sekcji strony.
Szybkie wdrożenie w projekt
Powyższe informacje powinny być wystarczające do tego, aby wykonać zadanie i dokończyć ten projekt. Jest to jednak tylko pobieżny przegląd jego struktury – głębszą wiedzę na jego temat zdobędziesz, analizując jego działanie w trakcie pracy nad nim.
Wiemy, że takie wskoczenie na głębokie wody projektu może być dla Ciebie frustrujące – ale właśnie dlatego to zadanie znalazło się w tym module. Jesteś już na tym etapie kursu, na którym musisz myśleć o swojej przyszłej pracy jako Junior Web Developer.
Oczywiście, byłoby idealnie, gdyby dołączenie do projektu wiązało się z paroma tygodniami wdrożenia. Może jednak zdarzyć się inaczej – czasami programista musi być gotowy do wskoczenia do pędzącego projektu, którego termin już minął, a prawnik klienta wysyła pozdrowienia do działu obsługi.
W takiej sytuacji możesz nie mieć czasu na spokojne zapoznanie się z projektem. Musisz spróbować poradzić sobie z postawionym przed Tobą zadaniem, wdrażając się w projekt tylko na tyle, na ile wymaga tego rozwiązanie problemu.
Dlatego wykorzystaj tę okazję do sprawdzenia się w takiej sytuacji. Wiesz, że jest to projekt reactowy, o strukturze bardzo podobnej do wcześniejszej aplikacji. Mało tego, wiesz co dokładnie jest do zrobienia (opis poniżej), więc spróbuj nie przejmować się tym, że nie znasz każdego zakamarka projektu.